﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Xna.Framework.Input;
using ProjetCom.Model.CasseBriques;
using ProjetCom.Vue;
using ProjetCom.Model.Template;

namespace ProjetCom.Ctrl
{
    class CtrlBriques : CtrlTemplate
    {
        private List<Element> m_elements;
        private List<Barre> m_barre;
        private Balle m_Balle;
        private int m_NumberLevel;
        private int m_Life;

        public int Life
        {
            get { return m_Life; }
        }

        public List<Element> Elements
        {
            get { return m_elements; }
        }

        public Boolean EndLevel
        {
            get { return !m_elements.Exists(new Predicate<Element>(delegate(Element e) { return (e.Name != "Balle" && e.Name != "Barre"); })); }
        }

        public CtrlBriques(IServiceProvider p_serviceProvider, int p_score) :
            base(p_serviceProvider, p_score)
        {
            m_NumberLevel = 1;
            ChargerLevel();
            m_Level = new LevelBriques(p_serviceProvider, this);
            m_Life = 3;
        }

        private void ChargerLevel()
        {
            int widthTmp;
            List<string> lines = new List<string>();
            try
            {
                using (StreamReader reader = new StreamReader(Path.Combine("Content/Briques/level" + m_NumberLevel + ".txt")))
                {
                    string line = reader.ReadLine();
                    string[] BlockEntries = line.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    widthTmp = BlockEntries.Count();
                    while (line != null)
                    {
                        lines.Add(line);
                        BlockEntries = line.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        if (BlockEntries.Count() != widthTmp)
                            throw new Exception(String.Format("La taille de la ligne {0} est differente de la précédente.", lines.Count));
                        line = reader.ReadLine();
                    }
                }

                // Alloue la grille
                m_elements = new List<Element>();
                m_barre = new List<Barre>();

                // Boucle sur toutes les positions
                for (int y = 0; y < lines.Count; ++y)
                {
                    for (int x = 0; x < widthTmp; ++x)
                    {
                        // to load each block.
                        string[] blockEntries = lines[y].Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        char blockType = blockEntries[x].ToCharArray()[0];

                        if (blockType != '.')
                            m_elements.Add(SelectionBlock(blockType, x, y));
                    }
                }
            }
            catch
            {
                this.ReturnMenu = true;
            }
        }

        private Element SelectionBlock(char p_Type, int p_x, int p_y)
        {
            switch (p_Type)
            {
                // Brique
                case 'b': return new Brique(p_x, p_y, 1);
                case 'B': return new Brique(p_x, p_y, 2);

                // Barre
                case 'r':
                    Barre barre = new Barre(p_x, p_y);
                    m_barre.Add(barre);
                    return barre;

                // Point de départ
                case 'o':
                    m_Balle = new Balle(p_x, p_y, -80, -40);
                    return m_Balle;

                // Block inexistant
                default: throw new NotSupportedException(String.Format("Carractère non supporté '{0}'.", p_Type));
            }
        }

        public override void Update(Microsoft.Xna.Framework.GameTime _gameTime)
        {
            foreach (Element element in m_elements)
            {
                element.Update(_gameTime);
            }

            if (!TestCollisionBalleElement())
            {
                TestSortieBalle();
            }
            else
            {
                m_Score += 100 * m_NumberLevel;
            }

            if (this.EndLevel)
            {
                m_NumberLevel++;
                m_Life += 1;
                ChargerLevel();
            }
            
        }

        private void TestSortieBalle()
        {
            if (m_Balle.X <= 0)
            {
                //Console.WriteLine("Collision par la paroie gauche");
                m_Balle.X = 1;
                m_Balle.Collision(Element.CoteCollision.left);
            }
            else if ((m_Balle.X + Element.Width) >= 1280)
            {
                //Console.WriteLine("Collision par la paroie droite");
                m_Balle.X = 1279 - Element.Width;
                m_Balle.Collision(Element.CoteCollision.right);
            }

            if (m_Balle.Y < 0)
            {
                //Console.WriteLine("Collision par la paroie haute");
                m_Balle.Y = 1;
                m_Balle.Collision(Element.CoteCollision.top);
            }
            else if ((m_Balle.Y + Element.Height * 2) >= 720)
            {
                Console.WriteLine("Sortie par le bas");
                if (--m_Life == 0)
                {
                    //Console.WriteLine("#############################\n\tFin du programme\n#############################");
                    ReturnMenu = true;
                }
                else
                {
                    m_elements.Remove(m_Balle);
                    m_Balle = new Balle(10, 9, -80, -40);
                    m_elements.Add(m_Balle);
                }
            }
        }

        public bool TestCollisionBalleElement()
        {
            foreach (Element element in m_elements)
            {
                if (element != m_Balle)
                {
                    Element.CoteCollision coteCollision = element.EnterCollision(m_Balle);

                    // Pas de réaction si pas de collision
                    if (coteCollision != Element.CoteCollision.none)
                    {
                        Console.WriteLine("Collision between '" + m_Balle.Name + "' and '" + element.Name + "' at the '" + coteCollision + "' of '" + element.Name + "'.");
                        m_Balle.Collision(coteCollision, element.IsMoove);

                        // Pas besoin de savoir le coté exact pour l'élément
                        element.Collision(coteCollision);

                        if (!element.IsAlive)
                        {
                            m_elements.Remove(element);
                        }

                        return true;
                    }
                }
            }

            return false;
        }

        public override void EventClavier()
        {
            // Get input state.
            KeyboardState keyboardState = Keyboard.GetState();


            if (!m_barre.Exists(new Predicate<Barre>(delegate(Barre b) { return !b.CanMooveLeft(); })) && keyboardState.IsKeyDown(Keys.Left))
            {
                foreach (Barre barre in m_barre)
                {
                        barre.MooveLeft();
                }
            }
            
            else if (!m_barre.Exists(new Predicate<Barre>(delegate(Barre b) { return !b.CanMooveRight(); })) && keyboardState.IsKeyDown(Keys.Right))
            {
                foreach (Barre barre in m_barre)
                {
                        barre.MooveRight();
                }
            }
        }
    }
}
